<script setup lang="ts">
import { ref, watch, computed, onMounted } from 'vue'

interface Props {
  selecteds?: string[] // 已选标签
  data?: Record<string, number> // 标签数据 {标签名: 数量}
  showAll?: boolean // 是否显示"全部"标签
  allText?: string // "全部"标签的文本
}

const props = withDefaults(defineProps<Props>(), {
  selecteds: () => [],
  data: () => ({}),
  showAll: true,
  allText: '全部'
})

const emit = defineEmits(['update:selecteds', 'change'])

// 容器和标签元素的引用
const containerRef = ref<HTMLElement | null>(null)
const tagRefs = ref<HTMLElement[]>([])

// 可见标签与隐藏标签
const visibleTags = ref<string[]>([])
const hiddenTags = ref<string[]>([])
// 本地状态
const selectedTags = ref<string[]>([...props.selecteds])
const tabData = computed(() => {
  const result = { ...props.data }

  // 如果显示"全部"标签且数据中没有"全部"，则添加"全部"
  if (props.showAll && !result[props.allText]) {
    result[props.allText] = Object.values(result).reduce((sum, count) => sum + count, 0)
  }

  return result
})

// 标签列表（确保"全部"在最前面）
const tabKeys = computed(() => {
  const keys = Object.keys(tabData.value)
  if (props.showAll) {
    // 移除"全部"并重新添加到最前面
    const allIndex = keys.indexOf(props.allText)
    if (allIndex > -1) {
      keys.splice(allIndex, 1)
    }
    return [props.allText, ...keys]
  }
  return keys
})

// 标签是否被选中
const isSelected = (tag: string) => {
  return selectedTags.value.includes(tag)
}

// 是否有隐藏标签
const hasHiddenTags = computed(() => {
  return hiddenTags.value.length > 0
})

// 根据标签文本估算宽度
const estimateTagWidth = (tag: string): number => {
  // 标签文本: tag (count)
  const count = tabData.value[tag]
  const countText = count ? ` (${count})` : ''
  const fullText = `${tag}${countText}`

  // 估算宽度 = 字符数 * 平均字符宽度 + 内边距
  return tag.length * 14 + countText.length * 4 + 10
}

// 计算哪些标签可见，哪些需要隐藏
const calculateVisibleTags = () => {
  if (!containerRef.value || tabKeys.value.length === 0) return

  const container = containerRef.value
  const containerWidth = container.clientWidth
  const moreButtonWidth = 50 // 预留给"更多"按钮的宽度

  let availableWidth = containerWidth - moreButtonWidth
  let visibleCount = 0

  // 重置
  visibleTags.value = []
  hiddenTags.value = []

  // 计算可见标签数量
  for (let i = 0; i < tabKeys.value.length; i++) {
    const tag = tabKeys.value[i]
    const tagWidth = estimateTagWidth(tag)

    if (availableWidth >= tagWidth) {
      availableWidth -= tagWidth
      visibleCount++
    } else {
      break
    }
  }

  // 至少显示一个标签
  visibleCount = Math.max(1, visibleCount)

  // 分配标签到可见和隐藏数组
  visibleTags.value = tabKeys.value.slice(0, visibleCount)
  hiddenTags.value = tabKeys.value.slice(visibleCount)
}

/**
 * 处理标签点击
 */
const handleTabClick = (tag: string) => {
  let newSelectedTags: string[] = []

  // 如果点击的是"全部"标签
  if (tag === props.allText && props.showAll) {
    if (isSelected(tag)) {
      // 如果"全部"已选中，则取消所有选择
      newSelectedTags = []
    } else {
      // 如果"全部"未选中，则只选中"全部"
      newSelectedTags = [props.allText]
    }
  } else {
    // 如果点击的是其他标签
    if (isSelected(tag)) {
      // 如果标签已选中，则取消选择
      newSelectedTags = selectedTags.value.filter(t => t !== tag)
    } else {
      // 如果标签未选中，则添加到选中列表
      // 同时移除"全部"标签（如果存在）
      newSelectedTags = [
        ...selectedTags.value.filter(t => t !== props.allText),
        tag
      ]
    }
  }

  // 如果没有选中任何标签，则默认选中"全部"
  if (newSelectedTags.length === 0 && props.showAll) {
    newSelectedTags = [props.allText]
  }

  // 更新本地状态
  selectedTags.value = newSelectedTags

  // 更新父组件的值
  emit('update:selecteds', [...selectedTags.value])
  emit('change', [...selectedTags.value])
}

// 监听窗口大小变化
const handleResize = () => {
  calculateVisibleTags()
}

// 监听 props.selecteds 变化，同步到本地状态
watch(() => props.selecteds, (newVal) => {
  // 如果外部传入的是空数组，则默认选中"全部"
  if (newVal.length === 0 && props.showAll) {
    selectedTags.value = [props.allText]
  } else {
    selectedTags.value = [...newVal]
  }
}, { deep: true })

// 组件挂载时初始化
onMounted(() => {
  // 如果没有选中任何标签且显示"全部"标签，则默认选中"全部"
  if (selectedTags.value.length === 0 && props.showAll) {
    selectedTags.value = [props.allText]
    emit('update:selecteds', [props.allText])
  }

  // 添加窗口大小变化监听
  window.addEventListener('resize', handleResize)

  // 初始化计算可见标签
  nextTick(() => {
    calculateVisibleTags()
  })
})

// 监听tabKeys变化重新计算
watch(() => tabKeys.value, () => {
  nextTick(() => {
    calculateVisibleTags()
  })
}, { deep: true })

// 组件卸载时清理事件监听
onUnmounted(() => {
  window.removeEventListener('resize', handleResize)
})
</script>

<template>
  <div class="tab-selected-scroll" ref="containerRef">
    <div
      v-for="tag in visibleTags"
      :key="tag"
      :ref="(el) => { if (el) tagRefs[index] = el }"
      class="tab-item"
      :class="{ 'is-active': isSelected(tag) }"
      @click="handleTabClick(tag)"
    >
      {{ `${tag}${tabData[tag] ? ` (${tabData[tag]})` : ''}` }}
    </div>

    <el-popover v-if="hasHiddenTags" placement="bottom" :width="500" trigger="hover" popper-class="tab-popover">
      <template #reference>
        <div class="tab-item more-tags">
          <el-icon><ArrowDownBold /></el-icon>
        </div>
      </template>
      <template #default>
        <el-space class="tab-popover-content" wrap>
          <div
            v-for="tag in hiddenTags"
            :key="tag"
            class="tab-item-popover"
            :class="{ 'is-active': isSelected(tag) }"
            @click="handleTabClick(tag)"
          >
            {{ `${tag}${tabData[tag] ? ` (${tabData[tag]})` : ''}` }}
          </div>
        </el-space>
      </template>
    </el-popover>
  </div>
</template>

<style lang="scss" scoped>
@import "@@/assets/styles/main-page.scss";
@import "@@/assets/styles/mixins.scss";

.tab-selected-scroll {
  min-width: 0;
  max-width: 800px;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

:deep(.tab-item) {
  padding: 0 10px !important;
  cursor: pointer;
  white-space: nowrap;

  &:first-child {
    padding-left: 0 !important;
  }

  &:last-child {
    padding-right: 0 !important;
  }
}

.more-tags {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--el-text-color-regular);
  padding-left: 0 !important;
  margin-right: 10px !important;
}

:deep(.tab-item.is-active),
:deep(.tab-item:hover) {
  color: #00f3c7 !important;
}

.tab-popover-content {
  max-height: 300px;
  overflow-y: auto;
  @extend %scrollbar;
}

.tab-item-popover {
  padding: 8px 12px;
  cursor: pointer;

  &.is-active {
    color: #00f3c7 !important;
  }

  &:hover {
    background-color: var(--el-fill-color-light);
    color: #00f3c7 !important;
  }
}
</style>

